/* Copyright 2009 dnAnalytics Project.
 *
 * Contributors to this file:
 * Jurgen Van Gael
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this 
 *   list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of the dnAnalytics Project nor the names of its contributors
 *   may be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
using System;
using dnAnalytics.Properties;

namespace dnAnalytics.LinearAlgebra
{
    /// <summary>
    /// A matrix type for diagonal matrices. 
    /// </summary>
    /// <remarks>
    /// Diagonal matrices can be non-square matrices but the diagonal always starts
    /// at element 0,0. A diagonal matrix will throw an exception if non diagonal
    /// entries are set. The exception to this is when the off diagonal elements are
    /// 0.0 or NaN; these settings will cause no change to the diagonal matrix.
    /// </remarks>
    [Serializable]
    public partial class DiagonalMatrix : Matrix
    {
        /// <summary>
        /// The array containing the diagonal entries.
        /// </summary>
        private readonly double[] mData;

        /// <summary>
        /// Creates a square diagonal matrix with the given <paramref name="order"/>. The matrix values are the set to zero.
        /// </summary>
        /// <param name="order">The order of the new matrix.</param>
        /// <exception cref="ArgumentException">If either <paramref name="order"/> is less than one.</exception>
        public DiagonalMatrix(int order)
            : this(order, order)
        {
        }

        /// <summary>
        /// Creates a diagonal matrix with the given <paramref name="order"/>. The matrix values are the set to zero.
        /// </summary>
        /// <param name="order">The order of the new matrix.</param>
        /// <param name="val">The value that each diagonal element gets.</param>
        /// <exception cref="ArgumentException">If either <paramref name="order"/> is less than one.</exception>
        public DiagonalMatrix(int order, double val)
            : this(order, order, val)
        {
        }

        /// <summary>
        /// Creates a square diagonal matrix with the given number of <paramref name="rows"/> and <paramref name="columns"/>. 
        /// The matrix values are the set to zero.
        /// </summary>
        /// <param name="rows">The number of rows in the matrix.</param>
        /// <param name="columns">The number of columns in the matrix.</param>
        /// <exception cref="ArgumentException">If either <paramref name="rows"/> and <paramref name="columns"/> is less than one.</exception>
        public DiagonalMatrix(int rows, int columns)
            : base(rows, columns)
        {
            mData = new double[System.Math.Min(rows, columns)];
        }

        /// <summary>
        /// Creates a square diagonal matrix with the given number of <paramref name="rows"/> and <paramref name="columns"/>. 
        /// The matrix values are the set to zero.
        /// </summary>
        /// <param name="rows">The number of rows in the matrix.</param>
        /// <param name="columns">The number of columns in the matrix.</param>
        /// <param name="val">The value that each diagonal element gets.</param>
        /// <exception cref="ArgumentException">If either <paramref name="rows"/> and <paramref name="columns"/> is less than one.</exception>
        public DiagonalMatrix(int rows, int columns, double val)
            : base(rows, columns)
        {
            mData = new double[System.Math.Min(rows, columns)];
            for (int i = 0; i < mData.Length; i++)
            {
                mData[i] = val;
            }
        }

        /// <summary>
        /// Creates a new instance of the <see cref="DiagonalMatrix"/> class.
        /// </summary>
        /// <remarks>
        /// <param name="source">
        /// The <see cref="DiagonalMatrix"/> from which the data will be copied to the new instance.
        /// </param>
        public DiagonalMatrix(DiagonalMatrix source)
            : base(source.Rows, source.Columns)
        {
            mData = (double[]) source.mData.Clone();
        }

        /// <summary>
        /// Creates a new instance of the <see cref="DiagonalMatrix"/> class.
        /// </summary>
        /// <param name="source">The array of doubles from which the data will be
        /// copied to the diagonal.</param>
        public DiagonalMatrix(double[] source)
            : base(source.Length, source.Length)
        {
            mData = (double[]) source.Clone();
        }

        /// <summary>
        /// Creates a new instance of the <see cref="DiagonalMatrix"/> class.
        /// </summary>
        /// <param name="source">The array of doubles from which the data will be
        /// copied to the diagonal.</param>
        public DiagonalMatrix(Vector source)
            : base(source.Count, source.Count)
        {
            mData = new double[source.Count];
            for (int i = 0; i < source.Count; i++)
            {
                mData[i] = source[i];
            }
        }

        /// <summary>
        /// Returns a reference to the data for the diagonal matrix.
        /// </summary>
        internal double[] Data
        {
            get { return mData; }
        }

        /// <summary>
        /// Creates a <see cref="Matrix"/> for the given number of rows and columns.
        /// </summary>
        /// <param name="numberOfRows">The number of rows.</param>
        /// <param name="numberOfColumns">The number of columns.</param>
        /// <returns>
        /// A <see cref="Matrix"/> with the given dimensions.
        /// </returns>
        protected internal override Matrix CreateMatrix(int numberOfRows, int numberOfColumns)
        {
            return new DiagonalMatrix(numberOfRows, numberOfColumns);
        }

        /// <summary>
        /// Creates a <see cref="Vector"/> with a the given dimension.
        /// </summary>
        /// <param name="size">The size of the vector.</param>
        /// <returns>
        /// A <see cref="Vector"/> with the given dimension.
        /// </returns>
        protected internal override Vector CreateVector(int size)
        {
            return new SparseVector(size);
        }

        /// <summary>
        /// Retrieves the value at the given indices. <strong>This method is not ranged checked.</strong> If the
        /// indices are outside the dimensions of the matrix, it may return an incorrect value or throw
        /// an <see cref="IndexOutOfRangeException"/>.
        /// </summary>
        /// <param name="row">The row index.</param>
        /// <param name="column">The column index.</param>
        /// <returns>The value at the given indices.</returns>
        /// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/>
        /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
        protected internal override double ValueAt(int row, int column)
        {
            if (row == column)
            {
                return mData[row];
            }

            return 0.0;
        }

        /// <summary>
        /// Set the value at the given indices to the given value. <strong>This method is not ranged checked.</strong> If the
        /// indices are outside the dimensions of the matrix, it may set an incorrect element or throw
        /// an <see cref="IndexOutOfRangeException"/>.
        /// </summary>
        /// <param name="row">The row index.</param>
        /// <param name="column">The column index.</param>
        /// <param name="value">The value to set.</param>
        /// <exception cref="IndexOutOfRangeException">When trying to set an off diagonal element.</exception>
        /// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/>
        /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
        protected internal override void ValueAt(int row, int column, double value)
        {
            if (row == column)
            {
                mData[row] = value;
            }
            else if(value != 0.0 && !Double.IsNaN(value))
            {
                throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix.");
            }
        }

        /// <summary>
        /// Adds two matrices together and returns the results.
        /// </summary>
        /// <param name="leftSide">One of the matrices to add.</param>
        /// <param name="rightSide">One of the matrices to add.</param>
        /// <returns>The result of the addition.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator +(DiagonalMatrix leftSide, DiagonalMatrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (leftSide.Rows != rightSide.Rows || leftSide.Columns != rightSide.Columns)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }

            DiagonalMatrix ret = new DiagonalMatrix(leftSide);
            ret.Add(rightSide);
            return ret;
        }

        /// <summary>
        /// Negates each element of the matrix.
        /// </summary>
        /// <param name="rightSide">The matrix to negate.</param>
        /// <returns>A matrix containing the negated values.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator -(DiagonalMatrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            DiagonalMatrix ret = new DiagonalMatrix(rightSide);
            ret.Negate();
            return ret;
        }

        /// <summary>
        /// Subtracts two matrices and returns the results.
        /// </summary>
        /// <param name="leftSide">The matrix to subtract from.</param>
        /// <param name="rightSide">The matrix to subtract.</param>
        /// <returns>The result of the subtraction.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator -(DiagonalMatrix leftSide, DiagonalMatrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (leftSide.Rows != rightSide.Rows || leftSide.Columns != rightSide.Columns)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }

            DiagonalMatrix ret = new DiagonalMatrix(leftSide);
            ret.Subtract(rightSide);
            return ret;
        }

        /// <summary>
        /// Divides a <strong>Matrix</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to divide.</param>
        /// <param name="rightSide">The constant to divide the matrix by.</param>
        /// <returns>The result of the division.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator /(DiagonalMatrix leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }
            DiagonalMatrix ret = new DiagonalMatrix(leftSide);
            ret.Divide(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The constant to multiply the matrix by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator *(DiagonalMatrix leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }
            DiagonalMatrix ret = new DiagonalMatrix(leftSide);
            ret.Multiply(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The constant to multiply the matrix by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static DiagonalMatrix operator *(double leftSide, DiagonalMatrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            DiagonalMatrix ret = new DiagonalMatrix(rightSide);
            ret.Multiply(leftSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <strong>Matrix</strong> and a <see cref="Vector"/>.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The vector to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <strong>leftSide.Columns ! = rightSide.Count</strong>.</exception>
        public static Vector operator *(DiagonalMatrix leftSide, Vector rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }

            if (leftSide.Columns != rightSide.Count)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }

            return leftSide.Multiply(rightSide);
        }

        /// <summary>
        /// Multiplies a <see cref="Vector"/> and a <strong>Matrix</strong>.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The matrix to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <strong>leftSide.Count != rightSide.Rows</strong>.</exception>
        public static Vector operator *(Vector leftSide, DiagonalMatrix rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }

            if (leftSide.Count != rightSide.Rows)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }

            return rightSide.LeftMultiply(leftSide);
        }

        /// <summary>
        /// Sets all values to zero.
        /// </summary>
        public override void Clear()
        {
            Array.Clear(mData, 0, Rows);
        }

        /// <summary>
        /// Copies a column into to the given vector.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="result">The vector to copy the column into.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of columns.</exception>        
        /// <exception cref="NotConformableException">If the result vector is of the incorrect size.</exception>
        public override void GetColumn(int index, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (index >= Columns || index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            if (result.Count != Rows)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result and copy the diagonal entry.
            result.Clear();
            if (index < mData.Length)
            {
                result[index] = mData[index];
            }
        }

        /// <summary>
        /// Copies the requested column elements into the given vector.
        /// </summary>
        /// <param name="columnIndex">The column to copy elements from.</param>
        /// <param name="rowIndex">The row to start copying from.</param>
        /// <param name="length">The number of elements to copy.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
        /// <exception cref="ArgumentNullException">If the result <see cref="Vector"/> is <see langword="null" />.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is negative,
        /// or greater than or equal to the number of columns.</exception>        
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is negative,
        /// or greater than or equal to the number of rows.</exception>        
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> + <paramref name="length"/>  
        /// is greater than or equal to the number of rows.</exception>
        /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
        /// <exception cref="NotConformableException">If <strong>result.Count &lt; length</strong>.</exception>
        public override void GetColumn(int columnIndex, int rowIndex, int length, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (columnIndex >= Columns || columnIndex < 0)
            {
                throw new ArgumentOutOfRangeException("columnIndex");
            }
            if (rowIndex >= Rows || rowIndex < 0)
            {
                throw new ArgumentOutOfRangeException("rowIndex");
            }

            if (rowIndex + length > Rows)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            if (length < 1)
            {
                throw new ArgumentException(Resources.NotPositive, "length");
            }

            if (result.Count < length)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result and copy the diagonal entry.
            result.Clear();
            if (columnIndex >= rowIndex && columnIndex < rowIndex + length && columnIndex < mData.Length)
            {
                result[columnIndex - rowIndex] = mData[columnIndex];
            }
        }

        /// <summary>
        /// Copies a row into to the given <see cref="Vector"/>.
        /// </summary>
        /// <param name="index">The row to copy.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the row into.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of rows.</exception>
        /// <exception cref="NotConformableException">If <b>this.Columns != result.Count</b>.</exception>
        public override void GetRow(int index, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (index >= Rows
                || index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            if (result.Count != Columns)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result and copy the diagonal entry.
            result.Clear();
            if (index < mData.Length)
            {
                result[index] = mData[index];
            }
        }

        /// <summary>
        /// Copies the requested row elements into a new <see cref="Vector"/>.
        /// </summary>
        /// <param name="rowIndex">The row to copy elements from.</param>
        /// <param name="columnIndex">The column to start copying from.</param>
        /// <param name="length">The number of elements to copy.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
        /// <exception cref="ArgumentNullException">If the result <see cref="Vector"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is negative,
        /// or greater than or equal to the number of columns.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is negative,
        /// or greater than or equal to the number of rows.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> + <paramref name="length"/>
        /// is greater than or equal to the number of rows.</exception>
        /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
        /// <exception cref="NotConformableException">If <strong>result.Count &lt; length</strong>.</exception>
        public override void GetRow(int rowIndex, int columnIndex, int length, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (rowIndex >= Rows || rowIndex < 0)
            {
                throw new ArgumentOutOfRangeException("rowIndex");
            }
            if (columnIndex >= Columns || columnIndex < 0)
            {
                throw new ArgumentOutOfRangeException("columnIndex");
            }

            if (columnIndex + length > Columns)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            if (length < 1)
            {
                throw new ArgumentException(Resources.NotPositive, "length");
            }

            if (result.Count < length)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result and copy the diagonal entry.
            result.Clear();
            if (rowIndex >= columnIndex && rowIndex < columnIndex + length && rowIndex < mData.Length)
            {
                result[rowIndex - columnIndex] = mData[rowIndex];
            }
        }

        /// <summary>
        /// Copies the elements of this matrix to the given matrix.
        /// </summary>
        /// <param name="target">The matrix to copy values into.</param>
        /// <exception cref="ArgumentNullException">If target is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If target is not the same size as this matrix.</exception>
        public override void CopyTo(Matrix target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            if ((target.Rows != Rows) || (target.Columns != Columns))
            {
                throw new NotConformableException("target", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(this, target))
            {
                return;
            }

            SparseMatrix matrix = target as SparseMatrix;
            if (matrix != null)
            {
                int[] indx = new int[mData.Length];
                for (int i = 0; i < Rows; i++)
                {
                    indx[i] = i;
                }

                // copy the row indices
                matrix.mRowIndices = new int[mData.Length];
                Buffer.BlockCopy(indx, 0, matrix.mRowIndices, 0, mData.Length*Constants.SizeOfInt);

                // copy the column indices.
                matrix.mColumnIndices = new int[mData.Length];
                Buffer.BlockCopy(indx, 0, matrix.mColumnIndices, 0, mData.Length*Constants.SizeOfInt);

                // copy the data.
                matrix.mValues = new double[mData.Length];
                Buffer.BlockCopy(mData, 0, matrix.mValues, 0, mData.Length*Constants.SizeOfDouble);
            }
            else
            {
                // Clear the target matrix
                target.Clear();

                // Standard copy.
                for (int i = 0; i < mData.Length; i++)
                {
                    target[i, i] = mData[i];
                }
            }
        }

        /// <summary>
        /// Returns a deep-copy clone of the <b>Matrix</b>.
        /// </summary>
        /// <returns>A deep-copy clone of the <b>Matrix</b>.</returns>
        public override Matrix Clone()
        {
            return new DiagonalMatrix(this);
        }

        /// <summary>Calculates the L1 norm.</summary>
        /// <returns>The L1 norm of the matrix.</returns>
        public override double L1Norm()
        {
            double norm = double.NegativeInfinity;
            for (int i = 0; i < mData.Length; i++)
            {
                norm = System.Math.Max(norm, System.Math.Abs(mData[i]));
            }

            return norm;
        }

        /// <summary>Calculates the L2 norm.</summary>
        /// <returns>The L2 norm of the matrix.</returns>
        public override double L2Norm()
        {
            double maxSV = double.NegativeInfinity;
            for (int i = 0; i < mData.Length; i++)
            {
                maxSV = System.Math.Max(maxSV, System.Math.Abs(mData[i]));
            }

            return maxSV;
        }

        /// <summary>Calculates the Frobenius norm of this matrix.</summary>
        /// <returns>The Frobenius norm of this matrix.</returns>
        public override double FrobeniusNorm()
        {
            double norm = 0;
            for (int i = 0; i < mData.Length; i++)
            {
                norm += mData[i]*mData[i];
            }

            return System.Math.Sqrt(norm);
        }

        /// <summary>Calculates the infinity norm of this matrix.</summary>
        /// <returns>The infinity norm of this matrix.</returns>      
        public override double InfinityNorm()
        {
            return L1Norm();
        }

        /// <summary>Calculates the condition number of this matrix.</summary>
        /// <returns>The condition number of the matrix.</returns>
        public override double ConditionNumber()
        {
            double maxSV = double.NegativeInfinity;
            double minSV = double.PositiveInfinity;
            for (int i = 0; i < mData.Length; i++)
            {
                maxSV = System.Math.Max(maxSV, System.Math.Abs(mData[i]));
                minSV = System.Math.Min(minSV, System.Math.Abs(mData[i]));
            }

            return maxSV/minSV;
        }

        /// <summary>
        /// Returns the transpose of this matrix.
        /// </summary>
        /// <returns>The transpose of this matrix as a <see cref="DiagonalMatrix"/>.</returns>
        public override Matrix Transpose()
        {
            return new DiagonalMatrix(this);
        }

        /// <summary>
        /// Returns the inverse of this matrix by inverting all diagonal elements.
        /// </summary>
        /// <returns>The inverse of this matrix as a <see cref="DiagonalMatrix"/>.</returns>
        /// <exception cref="SingularMatrixException">When the diagonal matrix is singular.</exception>
        /// <exception cref="MatrixNotSquareException">When the matrix is not square.</exception>
        public override Matrix Inverse()
        {
            if (this.Rows != this.Columns)
            {
                throw new MatrixNotSquareException();
            }

            DiagonalMatrix D = new DiagonalMatrix(this);
            for (int i = 0; i < mData.Length; i++)
            {
                if (this[i, i] != 0.0)
                {
                    D[i, i] = 1.0 / this[i, i];
                }
                else
                {
                    throw new SingularMatrixException();
                }
            }

            return D;
        }

        /// <summary>
        /// Returns a new matrix containing the lower triangle of this matrix.
        /// </summary>
        /// <returns>The lower triangle of this matrix as a <see cref="DiagonalMatrix"/>.</returns>        
        public override Matrix GetLowerTriangle()
        {
            return new DiagonalMatrix(this);
        }

        /// <summary>
        /// Puts the lower triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public override void GetLowerTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if ((result.Rows != Rows)
                || (result.Columns != Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(this, result))
            {
                return;
            }

            result.Clear();

            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }
        }

        /// <summary>
        /// Returns a new matrix containing the lower triangle of this matrix. The new matrix
        /// does not contain the diagonal elements of this matrix.
        /// </summary>
        /// <returns>The lower triangle of this matrix as a <see cref="DiagonalMatrix"/>.</returns>
        public override Matrix GetStrictlyLowerTriangle()
        {
            return new DiagonalMatrix(Rows);
        }

        /// <summary>
        /// Puts the strictly lower triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public override void GetStrictlyLowerTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if ((result.Rows != Rows) || (result.Columns != Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            result.Clear();
        }

        /// <summary>
        /// Returns a new matrix containing the upper triangle of this matrix.
        /// </summary>
        /// <returns>The upper triangle of this matrix as a <see cref="DiagonalMatrix"/>.</returns>   
        public override Matrix GetUpperTriangle()
        {
            return new DiagonalMatrix(this);
        }

        /// <summary>
        /// Puts the upper triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public override void GetUpperTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if ((result.Rows != Rows) || (result.Columns != Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(this, result))
            {
                return;
            }

            result.Clear();

            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }
        }

        /// <summary>
        /// Returns a new matrix containing the upper triangle of this matrix. The new matrix
        /// does not contain the diagonal elements of this matrix.
        /// </summary>
        /// <returns>The upper triangle of this matrix as a <see cref="DiagonalMatrix"/>.</returns>
        public override Matrix GetStrictlyUpperTriangle()
        {
            return new DiagonalMatrix(Rows);
        }

        /// <summary>
        /// Puts the strictly upper triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public override void GetStrictlyUpperTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if ((result.Rows != Rows) || (result.Columns != Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            result.Clear();
        }

        /// <summary>
        /// Creates a matrix that contains the values from the requested sub-matrix.
        /// </summary>
        /// <param name="rowIndex">The row to start copying from.</param>
        /// <param name="rowLength">The number of rows to copy. Must be positive.</param>
        /// <param name="columnIndex">The column to start copying from.</param>
        /// <param name="columnLength">The number of columns to copy. Must be positive.</param>
        /// <exception cref="ArgumentOutOfRangeException">If: <list><item><paramref name="rowIndex"/> is
        /// negative, or greater than or equal to the number of rows.</item>
        /// <item><paramref name="columnIndex"/> is negative, or greater than or equal to the number 
        /// of columns.</item>
        /// <item><c>(columnIndex + columnLength) &gt;= Columns</c></item>
        /// <item><c>(rowIndex + rowLength) &gt;= Rows</c></item></list></exception>        
        /// <exception cref="ArgumentException">If <paramref name="rowLength"/> or <paramref name="columnLength"/>
        /// is not positive.</exception>
        /// <returns>The resulting submatrix as a <see cref="SparseMatrix"/>.</returns>
        public override Matrix GetSubMatrix(int rowIndex, int rowLength, int columnIndex, int columnLength)
        {
            if (rowIndex >= Rows || rowIndex < 0)
            {
                throw new ArgumentOutOfRangeException("rowIndex");
            }

            if (columnIndex >= Columns || columnIndex < 0)
            {
                throw new ArgumentOutOfRangeException("columnIndex");
            }

            if (rowLength < 1)
            {
                throw new ArgumentException(Resources.NotPositive, "rowLength");
            }
            if (columnLength < 1)
            {
                throw new ArgumentException(Resources.NotPositive, "columnLength");
            }
            int colMax = columnIndex + columnLength;
            int rowMax = rowIndex + rowLength;

            if (rowMax > Rows)
            {
                throw new ArgumentOutOfRangeException("rowLength");
            }

            if (colMax > Columns)
            {
                throw new ArgumentOutOfRangeException("columnLength");
            }

            SparseMatrix result = new SparseMatrix(rowLength, columnLength);

            if (rowIndex > columnIndex && columnIndex + columnLength > rowIndex)
            {
                for (int i = 0; rowIndex - columnIndex + i < System.Math.Min(columnLength, rowLength); i++)
                {
                    result[i, rowIndex - columnIndex + i] = mData[rowIndex + i];
                }
            }
            else if (rowIndex < columnIndex && rowIndex + rowLength > columnIndex)
            {
                for (int i = 0; rowIndex - columnIndex + i < System.Math.Min(columnLength, rowLength); i++)
                {
                    result[columnIndex - rowIndex + i, i] = mData[columnIndex + i];
                }
            }
            else
            {
                for (int i = 0; i < System.Math.Min(columnLength, rowLength); i++)
                {
                    result[i, i] = mData[rowIndex + i];
                }
            }

            return result;
        }

        /// <summary>
        /// Returns this matrix as a multidimensional array.
        /// </summary>
        /// <returns>a multidimensional containing the values of this matrix.</returns>        
        public override double[,] ToArray()
        {
            double[,] result = new double[Rows,Columns];
            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }
            return result;
        }

        /// <summary>
        /// Creates a new sparse matrix and inserts the given column at the given index.
        /// </summary>
        /// <param name="columnIndex">The index of where to insert the column.</param>
        /// <param name="column">The column to insert.</param>
        /// <returns>A new <see cref="SparseMatrix"/> with the inserted column.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="column "/> is <see langword="null" />. </exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is &lt; zero or &gt; the number of columns.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="column"/> != the number of rows.</exception>
        public override Matrix InsertColumn(int columnIndex, Vector column)
        {
            if (column == null)
            {
                throw new ArgumentNullException("column");
            }
            if (columnIndex < 0 || columnIndex > this.Columns)
            {
                throw new ArgumentOutOfRangeException("columnIndex");
            }
            if (column.Count != this.Rows)
            {
                throw new NotConformableException("row", Resources.ParameterNotConformable);
            }
            Matrix result = new SparseMatrix(this.Rows, this.Columns + 1);
            for (int index = 0; index < columnIndex; index++)
            {
                result.SetColumn(index, GetColumn(index));
            }

            result.SetColumn(columnIndex, column);

            for (int index = columnIndex + 1; index < this.Columns + 1; index++)
            {
                result.SetColumn(index, GetColumn(index - 1));
            }
            return result;
        }

        /// <summary>
        /// Creates a new sparsematrix and inserts the given row at the given index.
        /// </summary>
        /// <param name="rowIndex">The index of where to insert the row.</param>
        /// <param name="row">The row to insert.</param>
        /// <returns>A new <see cref="SparseMatrix"/> with the inserted column.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />. </exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is &lt; zero or &gt; the number of rows.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="row"/> != the number of columns.</exception>
        public override Matrix InsertRow(int rowIndex, Vector row)
        {
            if (row == null)
            {
                throw new ArgumentNullException("row");
            }
            if (rowIndex < 0 || rowIndex > this.Rows)
            {
                throw new ArgumentOutOfRangeException("rowIndex");
            }
            if (row.Count != this.Columns)
            {
                throw new NotConformableException("row", Resources.ParameterNotConformable);
            }

            Matrix result = new SparseMatrix(this.Rows + 1, this.Columns);
            for (int index = 0; index < rowIndex; index++)
            {
                result.SetRow(index, GetRow(index));
            }
            result.SetRow(rowIndex, row);

            for (int index = rowIndex + 1; index < this.Rows + 1; index++)
            {
                result.SetRow(index, GetRow(index - 1));
            }
            return result;
        }

        /// <summary>
        /// Stacks this matrix on top of the given matrix and returns the combined matrix.
        /// </summary>
        /// <param name="lower">The matrix to stack this matrix upon.</param>
        /// <returns>The combined matrix as a <see cref="SparseMatrix"/>.</returns>
        /// <exception cref="ArgumentNullException">If lower is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <strong>upper.Columns != lower.Columns</strong>.</exception>
        public override Matrix Stack(Matrix lower)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower");
            }

            if (lower.Columns != Columns)
            {
                throw new NotConformableException("lower", Resources.ParameterNotConformable);
            }

            Matrix result = new SparseMatrix(Rows + lower.Rows, Columns);
            Stack(lower, result);
            return result;
        }

        /// <summary>
        /// Stacks this matrix on top of the given matrix and places the result into the result matrix.
        /// </summary>
        /// <param name="lower">The matrix to stack this matrix upon.</param>
        /// <param name="result">The combined matrix.</param>
        /// <exception cref="ArgumentNullException">If lower is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If <strong>upper.Columns != lower.Columns</strong>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not (this.Rows + lower.rows) x this.Columns.</exception>
        public override void Stack(Matrix lower, Matrix result)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (lower.Columns != Columns)
            {
                throw new NotConformableException("lower", Resources.ParameterNotConformable);
            }

            if ((result.Rows != (Rows + lower.Rows)) || (result.Columns != Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result matrix
            result.Clear();

            // Copy the diagonal part into the result matrix.
            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }

            // Copy the lower matrix into the result matrix.
            for (int i = 0; i < lower.Rows; i++)
            {
                for (int j = 0; j < lower.Columns; j++)
                {
                    result[i + Rows, j] = lower[i, j];
                }
            }
        }

        /// <summary>
        /// Concatenates this matrix with the given matrix.
        /// </summary>
        /// <param name="right">The matrix to concatenate.</param>
        /// <returns>The combined matrix as a SparseMatrix.</returns>
        /// <exception cref="ArgumentNullException">If right is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <strong>this.Rows != right.Rows.</strong></exception>
        public override Matrix Append(Matrix right)
        {
            if (right == null)
            {
                throw new ArgumentNullException("right");
            }

            if (right.Rows != Rows)
            {
                throw new NotConformableException("right", Resources.ParameterNotConformable);
            }

            Matrix result = new SparseMatrix(Rows, Columns + right.Columns);
            Append(right, result);
            return result;
        }

        /// <summary>
        /// Concatenates this matrix with the given matrix and places the result into the result matrix.
        /// </summary>
        /// <param name="right">The matrix to concatenate.</param>
        /// <param name="result">The combined matrix.</param>
        /// <exception cref="ArgumentNullException">If right is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If <strong>this.Rows != right.Rows</strong>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not this.Rows x (this.Columns + right.Columns).</exception>
        public override void Append(Matrix right, Matrix result)
        {
            if (right == null)
            {
                throw new ArgumentNullException("right");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (right.Rows != Rows)
            {
                throw new NotConformableException("right", Resources.ParameterNotConformable);
            }

            if ((result.Rows != Rows) || (result.Columns != (Columns + right.Columns)))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result matrix
            result.Clear();

            // Copy the diagonal part into the result matrix.
            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }

            // Copy the lower matrix into the result matrix.
            for (int i = 0; i < right.Rows; i++)
            {
                for (int j = 0; j < right.Columns; j++)
                {
                    result[i, j + Rows] = right[i, j];
                }
            }
        }

        /// <summary>
        /// Diagonally stacks his matrix on top of the given matrix and places the combined matrix into the result matrix.
        /// </summary>
        /// <param name="lower">The lower, right matrix.</param>
        /// <param name="result">The combined matrix</param>
        /// <exception cref="ArgumentNullException">If lower is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not (this.Rows + lower.rows) x (this.Columns + lower.Columns).</exception>
        public override void DiagonalStack(Matrix lower, Matrix result)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if ((result.Rows != (Rows + lower.Rows)) || (result.Columns != (Columns + lower.Columns)))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            // Clear the result matrix
            result.Clear();

            // Copy the diagonal part into the result matrix.
            for (int i = 0; i < mData.Length; i++)
            {
                result[i, i] = mData[i];
            }

            // Copy the lower matrix into the result matrix.
            for (int i = 0; i < lower.Rows; i++)
            {
                result[i + Rows, i + Rows] = lower[i, i];
            }
        }

        /// <summary>
        /// Pointwise multiplies this matrix with another matrix.
        /// </summary>
        /// <param name="other">The matrix to pointwise multiply with this one.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this matrix and <paramref name="other"/> are not the same size.</exception>
        /// <returns>the pointwise multiplication of the two matrices as a <see cref="DiagonalMatrix"/>.</returns>
        public override Matrix PointwiseMultiply(Matrix other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if ((other.Rows != Rows) || (other.Columns != Columns))
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            DiagonalMatrix D = new DiagonalMatrix(this);
            for (int i = 0; i < mData.Length; i++)
            {
                D[i, i] = mData[i]*other[i, i];
            }

            return D;
        }

        /// <summary>
        /// Multiplies this matrix with another matrix and returns the result. If <paramref name="other"/> is a 
        /// <see cref="DiagonalMatrix"/>, the result will be a new <see cref="DiagonalMatrix"/>. If <paramref name="other"/> is a 
        /// <see cref="SparseMatrix"/>, the result will be a <see cref="SparseMatrix"/>. In all other cases, the result 
        /// will be a <see cref="DenseMatrix"/>.
        /// </summary>
        /// <param name="other">The matrix to multiply with.</param>
        /// <exception cref="NotConformableException">If <strong>this.Columns != other.Rows</strong>.</exception>        
        /// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
        public override Matrix Multiply(Matrix other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (Columns != other.Rows)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            DiagonalMatrix matrixD = other as DiagonalMatrix;
            if (matrixD != null)
            {
                Matrix result = CreateMatrix(Rows, other.Columns);
                Multiply(other, result);
                return result;
            }

            SparseMatrix matrixS = other as SparseMatrix;
            if (matrixS != null)
            {
                Matrix resultS = new SparseMatrix(Rows, other.Columns);
                Multiply(other, resultS);
                return resultS;
            }

            Matrix resultD = new DenseMatrix(Rows, other.Columns);
            Multiply(other, resultD);
            return resultD;
        }

        /// <summary>
        /// Multiplies this matrix with another matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="other">The matrix to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If <strong>this.Columns != other.Rows</strong>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
        public override void Multiply(Matrix other, Matrix result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (Columns != other.Rows)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            if ((result.Rows != Rows) || (result.Columns != other.Columns))
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
            {
                Matrix tmp = result.CreateMatrix(result.Rows, result.Columns);
                Multiply(other, tmp);
                tmp.CopyTo(result);
            }
            else
            {
                // Clear the result matrix
                result.Clear();

                // Case 1: both the left and right hand side are diagonal matrices.
                DiagonalMatrix matrixD = other as DiagonalMatrix;
                if (matrixD != null)
                {
                    for (int r = 0; r < mData.Length; r++)
                    {
                        result[r, r] = mData[r] * matrixD.mData[r];
                    }
                    return;
                }

                // Case 2: the right hand side is a sparse matrix.
                // TODO handle this case properly.

                // Case 3: the right hand side is a dense matrix.
                for (int r = 0; r < mData.Length; r++)
                {
                    for (int c = 0; c < other.Columns; c++)
                    {
                        result[r, c] = mData[r] * other[r, c];
                    }
                }
            }
        }

        /// <summary>
        /// Multiplies this matrix with a vector and places the results into the result matrix.
        /// </summary>
        /// <param name="rightSide">The vector to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If rightSide is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null"/>.</exception>
        /// <exception cref="NotConformableException">If <strong>result.Count != this.Rows</strong>.</exception>
        /// <exception cref="NotConformableException">If <strong>this.Columns != rightSide.Count</strong>.</exception>
        public override void Multiply(Vector rightSide, Vector result)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (rightSide.Count != Columns)
            {
                throw new NotConformableException("rightSide", Resources.ParameterNotConformable);
            }

            if (result.Count != Rows)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(rightSide, result))
            {
                Vector tmp = result.CreateVector(result.Count);
                Multiply(rightSide, tmp);
                tmp.CopyTo(result);
            }
            else
            {
                // Clear the result vector
                result.Clear();

                // Multiply the elements in the vector with the corresponding diagonal element in this.
                for (int r = 0; r < mData.Length; r++)
                {
                    result[r] = mData[r]*rightSide[r];
                }
            }
        }

        /// <summary>
        /// Multiplies this matrix with a vector and places the results into the result matrix. Note the operation is vector * matrix.
        /// </summary>
        /// <param name="leftSide">The vector to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If leftSide is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>result.Count != this.Columns</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != leftSide.Count</b>.</exception>
        public override void LeftMultiply(Vector leftSide, Vector result)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (Rows != leftSide.Count)
            {
                throw new NotConformableException("leftSide");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Resources.NullParameterException);
            }

            if (Columns != result.Count)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(leftSide, result))
            {
                Vector tmp = result.CreateVector(result.Count);
                LeftMultiply(leftSide, tmp);
                tmp.CopyTo(result);
            }
            else
            {
                // Clear the result vector
                result.Clear();

                // Multiply the elements in the vector with the corresponding diagonal element in this.
                for (int r = 0; r < mData.Length; r++)
                {
                    result[r] = mData[r]*leftSide[r];
                }
            }
        }

        /// <summary>Computes the determinant of this matrix.</summary>
        /// <returns>The determinant of this matrix.</returns>
        public override double Determinant()
        {
            if (Rows != Columns)
            {
                throw new MatrixNotSquareException();
            }

            double det = 1.0;
            for (int i = 0; i < mData.Length; i++)
            {
                det *= mData[i];
            }

            return det;
        }
    }
}